/**
 * jquery.Jcrop.js v0.9.12
 * jQuery Image Cropping Plugin - released under MIT License 
 * Author: Kelly Hallman <khallman@gmail.com>
 * http://github.com/tapmodo/Jcrop
 * Copyright (c) 2008-2013 Tapmodo Interactive LLC {{{
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * }}}
 */

;(function($) {

	$.Jcrop = function(obj, opt) {
		var options = $.extend({}, $.Jcrop.defaults),
			docOffset,
			_ua = navigator.userAgent.toLowerCase(),
			is_msie = /msie/.test(_ua),
			ie6mode = /msie [1-6]\./.test(_ua);

		// Internal Methods {{{
		function px(n) {
			return Math.round(n) + 'px';
		}

		function cssClass(cl) {
			return options.baseClass + '-' + cl;
		}

		function supportsColorFade() {
			return $.fx.step.hasOwnProperty('backgroundColor');
		}

		function getPos(obj) //{{{
		{
			var pos = $(obj).offset();
			return [pos.left, pos.top];
		}
		//}}}
		function mouseAbs(e) //{{{
		{
			return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])];
		}
		//}}}
		function setOptions(opt) //{{{
		{
			if (typeof(opt) !== 'object') opt = {};
			options = $.extend(options, opt);

			$.each(['onChange', 'onSelect', 'onRelease', 'onDblClick'], function(i, e) {
				if (typeof(options[e]) !== 'function') options[e] = function() {};
			});
		}
		//}}}
		/**
		 * @desc {String} 开始拖拽
		 * @param {Object} mode 类型move
		 * @param {Object} pos  坐标
		 * @param {Object} touch
		 */
		function startDragMode(mode, pos, touch) //{{{
		{
			docOffset = getPos($img);
			Tracker.setCursor(mode === 'move' ? mode : mode + '-resize');

			if (mode === 'move') {
				return Tracker.activateHandlers(createMover(pos), doneSelect, touch);
			}

			var fc = Coords.getFixed();
			var opp = oppLockCorner(mode);
			var opc = Coords.getCorner(oppLockCorner(opp));

			Coords.setPressed(Coords.getCorner(opp));
			Coords.setCurrent(opc);
			
			Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect, touch);
		}
		//}}}

		function dragmodeHandler(mode, f) //{{{
		{
			
			return function(pos) {
				if (!options.aspectRatio) {
					switch (mode) {
						case 'e':
							pos[1] = f.y2;
							break;
						case 'w':
							pos[1] = f.y2;
							break;
						case 'n':
							pos[0] = f.x2;
							break;
						case 's':
							pos[0] = f.x2;
							break;
					}
				} else {
					switch (mode) {
						case 'e':
							pos[1] = f.y + 1;
							break;
						case 'w':
							pos[1] = f.y + 1;
							break;
						case 'n':
							pos[0] = f.x + 1;
							break;
						case 's':
							pos[0] = f.x + 1;
							break;
					}
				}
				Coords.setCurrent(pos);
				Selection.update();
			};
		}
		//}}}
		function createMover(pos) //{{{
		{
			var lloc = pos;
			KeyManager.watchKeys();

			return function(pos) {
				Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]);
				lloc = pos;

				Selection.update();
			};
		}
		//}}}
		function oppLockCorner(ord) //{{{
		{
			switch (ord) {
				case 'n':
					return 'sw';
				case 's':
					return 'nw';
				case 'e':
					return 'nw';
				case 'w':
					return 'ne';
				case 'ne':
					return 'sw';
				case 'nw':
					return 'se';
				case 'se':
					return 'nw';
				case 'sw':
					return 'ne';
			}
		}
		//}}}
		function createDragger(ord) //{{{
		{
			return function(e) {
				if (options.disabled) {
					return false;
				}
				if ((ord === 'move') && !options.allowMove) {
					return false;
				}

				// Fix position of crop area when dragged the very first time.
				// Necessary when crop image is in a hidden element when page is loaded.
				docOffset = getPos($img);

				btndown = true;
				startDragMode(ord, mouseAbs(e));
				e.stopPropagation();
				e.preventDefault();
				return false;
			};
		}
		//}}}
		function presize($obj, w, h) //{{{
		{
			var nw = $obj.width(),
				nh = $obj.height();
			if ((nw > w) && w > 0) {
				nw = w;
				nh = (w / $obj.width()) * $obj.height();
			}
			if ((nh > h) && h > 0) {
				nh = h;
				nw = (h / $obj.height()) * $obj.width();
			}
			xscale = $obj.width() / nw;
			yscale = $obj.height() / nh;
			$obj.width(nw).height(nh);
		}
		//}}}
		function unscale(c) //{{{
		{
			return {
				x: c.x * xscale,
				y: c.y * yscale,
				x2: c.x2 * xscale,
				y2: c.y2 * yscale,
				w: c.w * xscale,
				h: c.h * yscale
			};
		}
		//}}}
		function doneSelect(pos) //{{{
		{
			
			var c = Coords.getFixed();
			if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) {
				Selection.enableHandles();
				Selection.done();
			} else {
				Selection.release();
			}
			Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
		}
		//}}}
		function newSelection(e) //{{{
		{
			
			if (options.disabled) {
				return false;
			}
			if (!options.allowSelect) {
				return false;
			}
			btndown = true;
			docOffset = getPos($img);
			Selection.disableHandles();
			Tracker.setCursor('crosshair');
			var pos = mouseAbs(e);
			Coords.setPressed(pos);
			Selection.update();
			Tracker.activateHandlers(selectDrag, doneSelect, e.type.substring(0, 5) === 'touch');
			KeyManager.watchKeys();
			
			e.stopPropagation();
			e.preventDefault();
			return false;
		}
		//}}}
		function selectDrag(pos) //{{{
		{
			Coords.setCurrent(pos);
			Selection.update();
		}
		//}}}
		function newTracker() //{{{
		{
			var trk = $('<div></div>').addClass(cssClass('tracker'));
			if (is_msie) {
				trk.css({
					opacity: 0,
					backgroundColor: 'white'
				});
			}
			return trk;
		}

//		function newCircle() //{{{
//		{
//			var circle = $('<div class="rectangle"><div id="selcircle" class="circle"></div></div>');
//			if (is_msie) {
//				circle.css({
//					opacity: 0.1,
//					backgroundColor: 'red'
//				});
//			}
//			return circle;
//		}
		//}}}

		// }}}
		// Initialization {{{
		// Sanitize some options {{{
		if (typeof(obj) !== 'object') {
			obj = $(obj)[0];
		}
		if (typeof(opt) !== 'object') {
			opt = {};
		}
		// }}}
		setOptions(opt);
		// Initialize some jQuery objects {{{
		// The values are SET on the image(s) for the interface
		// If the original image has any of these set, they will be reset
		// However, if you destroy() the Jcrop instance the original image's
		// character in the DOM will be as you left it.
		var img_css = {
			border: 'none',
			visibility: 'visible',
			margin: 0,
			padding: 0,
			position: 'absolute',
			top: 0,
			left: 0,
		};

		var $origimg = $(obj),
			img_mode = true;

		if (obj.tagName == 'IMG') {
			// Fix size of crop image.
			// Necessary when crop image is within a hidden element when page is loaded.
			if ($origimg[0].width != 0 && $origimg[0].height != 0) {
				// Obtain dimensions from contained img element.
				$origimg.width($origimg[0].width);
				$origimg.height($origimg[0].height);
			} else {
				// Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0). 
				var tempImage = new Image();
				tempImage.src = $origimg[0].src;
				$origimg.width(tempImage.width);
				$origimg.height(tempImage.height);
			}

			var $img = $origimg.clone().removeAttr('id').css(img_css).show();

			$img.width($origimg.width());
			$img.height($origimg.height());
			$origimg.after($img).hide();

		} else {
			$img = $origimg.css(img_css).show();
			img_mode = false;
			if (options.shade === null) {
				options.shade = true;
			}
		}

		presize($img, options.boxWidth, options.boxHeight);

		var boundx = $img.width(),
			boundy = $img.height(),


			$div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
				position: 'relative',
				backgroundColor: options.bgColor
			}).insertAfter($origimg).append($img);

		if (options.addClass) {
			$div.addClass(options.addClass);
		}

		var $img2 = $('<div />'),

			$img_holder = $('<div />')
			.width('100%').height('100%').css({
				zIndex: 310,
				position: 'absolute',
				overflow: 'hidden'
			}),

			$hdl_holder = $('<div />')
			.width('100%').height('100%').css('zIndex', 320),

			$sel = $('<div />')
			.css({
				position: 'absolute',
				zIndex: 600
			}).dblclick(function() {
				var c = Coords.getFixed();
				options.onDblClick.call(api, c);
			}).insertBefore($img).append($img_holder, $hdl_holder);

		if (img_mode) {

			$img2 = $('<img />')
				.attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy),

				$img_holder.append($img2);
				
			 var parentdiv = $('<div class="rectangle" id="rectangle"><div id="selcircle" class="circle"></div></div>');
			 $img_holder.append(parentdiv);
		}

		if (ie6mode) {
			$sel.css({
				overflowY: 'hidden'
			});
		}

		var bound = options.boundary;
		var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({
			position: 'absolute',
			top: px(-bound),
			left: px(-bound),
			zIndex: 290
		}).mousedown(newSelection);
		
//		var $circle = newCircle().css({
//			position: 'absolute',
//
//			zIndex: 29999
//		}).mousedown(newSelection);
		
		/* }}} */
		// Set more variables {{{
		var bgcolor = options.bgColor,
			bgopacity = options.bgOpacity,
			xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true,
			btndown, animating, shift_down;

		docOffset = getPos($img);
		// }}}
		// }}}
		// Internal Modules {{{
		// Touch Module {{{ 

		//触摸对象
		var Touch = (function() {
			// Touch support detection function adapted (under MIT License)
			// from code by Jeffrey Sambells - http://github.com/iamamused/

			/**
			 * @desc {String} 是否支持触摸事件
			 */
			function hasTouchSupport() {
				var support = {},
					events = ['touchstart', 'touchmove', 'touchend'],
					el = document.createElement('div'),
					i;

				try {
					for (i = 0; i < events.length; i++) {
						var eventName = events[i];
						eventName = 'on' + eventName;
						var isSupported = (eventName in el);
						if (!isSupported) {
							el.setAttribute(eventName, 'return;');
							isSupported = typeof el[eventName] == 'function';
						}
						support[events[i]] = isSupported;
					}
					return support.touchstart && support.touchend && support.touchmove;
				} catch (err) {
					return false;
				}
			}
			/**
			 * 检查是否支持
			 */
			function detectSupport() {
				if ((options.touchSupport === true) || (options.touchSupport === false)) return options.touchSupport;
				else return hasTouchSupport();
			}
			return {
				//创建拖拽
				createDragger: function(ord) {
					return function(e) {
						if (options.disabled) {
							return false;
						}
						if ((ord === 'move') && !options.allowMove) {
							return false;
						}
						
						docOffset = getPos($img);
						btndown = true;
						startDragMode(ord, mouseAbs(Touch.cfilter(e)), true);
						e.stopPropagation();
						e.preventDefault();
						return false;
					};
				},
				//重新选取
				newSelection: function(e) {
					return newSelection(Touch.cfilter(e));
				},
				//获取坐标
				cfilter: function(e) {
					
					e.pageX = e.originalEvent.changedTouches[0].pageX;
					e.pageY = e.originalEvent.changedTouches[0].pageY;
					return e;
				},
				isSupported: hasTouchSupport,
				support: detectSupport()
			};
		}());
		
		// }}}
		// Coords Module {{{



		//绘制
		var Coords = (function() {
			var x1 = 0,
				y1 = 0,
				x2 = 0,
				y2 = 0,
				ox, oy;

			function setPressed(pos) //{{{
			{
				pos = rebound(pos);

				x2 = x1 = pos[0];
				y2 = y1 = pos[1];
			}
			//}}}
			function setCurrent(pos) //{{{
			{
				pos = rebound(pos);

				ox = pos[0] - x2;
				oy = pos[1] - y2;
				x2 = pos[0];
				y2 = pos[1];
			}
			//}}}
			function getOffset() //{{{
			{
				return [ox, oy];
			}
			//}}}
			function moveOffset(offset) //{{{
			{
				var ox = offset[0],
					oy = offset[1];

				if (0 > x1 + ox) {
					ox -= ox + x1;
				}
				if (0 > y1 + oy) {
					oy -= oy + y1;
				}

				if (boundy < y2 + oy) {
					oy += boundy - (y2 + oy);
				}
				if (boundx < x2 + ox) {
					ox += boundx - (x2 + ox);
				}

				x1 += ox;
				x2 += ox;
				y1 += oy;
				y2 += oy;
			}
			//}}}
			function getCorner(ord) //{{{
			{
				var c = getFixed();
				switch (ord) {
					case 'ne':
						return [c.x2, c.y];
					case 'nw':
						return [c.x, c.y];
					case 'se':
						return [c.x2, c.y2];
					case 'sw':
						return [c.x, c.y2];
				}
			}
			//}}}
			function getFixed() //{{{
			{
				if (!options.aspectRatio) {
					return getRect();
				}
				// This function could use some optimization I think...
				var aspect = options.aspectRatio,
					min_x = options.minSize[0] / xscale,


					//min_y = options.minSize[1]/yscale,
					max_x = options.maxSize[0] / xscale,
					max_y = options.maxSize[1] / yscale,
					rw = x2 - x1,
					rh = y2 - y1,
					rwa = Math.abs(rw),
					rha = Math.abs(rh),
					real_ratio = rwa / rha,
					xx, yy, w, h;

				if (max_x === 0) {
					max_x = boundx * 10;
				}
				if (max_y === 0) {
					max_y = boundy * 10;
				}
				if (real_ratio < aspect) {
					yy = y2;
					w = rha * aspect;
					xx = rw < 0 ? x1 - w : w + x1;

					if (xx < 0) {
						xx = 0;
						h = Math.abs((xx - x1) / aspect);
						yy = rh < 0 ? y1 - h : h + y1;
					} else if (xx > boundx) {
						xx = boundx;
						h = Math.abs((xx - x1) / aspect);
						yy = rh < 0 ? y1 - h : h + y1;
					}
				} else {
					xx = x2;
					h = rwa / aspect;
					yy = rh < 0 ? y1 - h : y1 + h;
					if (yy < 0) {
						yy = 0;
						w = Math.abs((yy - y1) * aspect);
						xx = rw < 0 ? x1 - w : w + x1;
					} else if (yy > boundy) {
						yy = boundy;
						w = Math.abs(yy - y1) * aspect;
						xx = rw < 0 ? x1 - w : w + x1;
					}
				}

				// Magic %-)
				if (xx > x1) { // right side
					if (xx - x1 < min_x) {
						xx = x1 + min_x;
					} else if (xx - x1 > max_x) {
						xx = x1 + max_x;
					}
					if (yy > y1) {
						yy = y1 + (xx - x1) / aspect;
					} else {
						yy = y1 - (xx - x1) / aspect;
					}
				} else if (xx < x1) { // left side
					if (x1 - xx < min_x) {
						xx = x1 - min_x;
					} else if (x1 - xx > max_x) {
						xx = x1 - max_x;
					}
					if (yy > y1) {
						yy = y1 + (x1 - xx) / aspect;
					} else {
						yy = y1 - (x1 - xx) / aspect;
					}
				}

				if (xx < 0) {
					x1 -= xx;
					xx = 0;
				} else if (xx > boundx) {
					x1 -= xx - boundx;
					xx = boundx;
				}

				if (yy < 0) {
					y1 -= yy;
					yy = 0;
				} else if (yy > boundy) {
					y1 -= yy - boundy;
					yy = boundy;
				}

				return makeObj(flipCoords(x1, y1, xx, yy));
			}
			//}}}
			function rebound(p) //{{{
			{
				if (p[0] < 0) p[0] = 0;
				if (p[1] < 0) p[1] = 0;

				if (p[0] > boundx) p[0] = boundx;
				if (p[1] > boundy) p[1] = boundy;

				return [Math.round(p[0]), Math.round(p[1])];
			}
			//}}}
			function flipCoords(x1, y1, x2, y2) //{{{
			{
				var xa = x1,
					xb = x2,
					ya = y1,
					yb = y2;
				if (x2 < x1) {
					xa = x2;
					xb = x1;
				}
				if (y2 < y1) {
					ya = y2;
					yb = y1;
				}
				return [xa, ya, xb, yb];
			}
			//}}}
			function getRect() //{{{
			{
				var xsize = x2 - x1,
					ysize = y2 - y1,
					delta;

				if (xlimit && (Math.abs(xsize) > xlimit)) {
					x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit);
				}
				if (ylimit && (Math.abs(ysize) > ylimit)) {
					y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit);
				}

				if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) {
					y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale);
				}
				if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) {
					x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale);
				}

				if (x1 < 0) {
					x2 -= x1;
					x1 -= x1;
				}
				if (y1 < 0) {
					y2 -= y1;
					y1 -= y1;
				}
				if (x2 < 0) {
					x1 -= x2;
					x2 -= x2;
				}
				if (y2 < 0) {
					y1 -= y2;
					y2 -= y2;
				}
				if (x2 > boundx) {
					delta = x2 - boundx;
					x1 -= delta;
					x2 -= delta;
				}
				if (y2 > boundy) {
					delta = y2 - boundy;
					y1 -= delta;
					y2 -= delta;
				}
				if (x1 > boundx) {
					delta = x1 - boundy;
					y2 -= delta;
					y1 -= delta;
				}
				if (y1 > boundy) {
					delta = y1 - boundy;
					y2 -= delta;
					y1 -= delta;
				}

				return makeObj(flipCoords(x1, y1, x2, y2));
			}
			//}}}
			function makeObj(a) //{{{
			{
				return {
					x: a[0],
					y: a[1],
					x2: a[2],
					y2: a[3],
					w: a[2] - a[0],
					h: a[3] - a[1]
				};
			}
			//}}}

			return {
				flipCoords: flipCoords,
				setPressed: setPressed,
				setCurrent: setCurrent,
				getOffset: getOffset,
				moveOffset: moveOffset,
				getCorner: getCorner,
				getFixed: getFixed
			};
		}());

		//}}}
		// Shade Module {{{
		var Shade = (function() {
			var enabled = false,
				holder = $('<div />').css({
					position: 'absolute',
					zIndex: 240,
					opacity: 0
				}),
				shades = {
					top: createShade(),
					left: createShade().height(boundy),
					right: createShade().height(boundy),
					bottom: createShade()
				};

			function resizeShades(w, h) {
				shades.left.css({
					height: px(h)
				});
				shades.right.css({
					height: px(h)
				});
			}

			function updateAuto() {
				return updateShade(Coords.getFixed());
			}

			function updateShade(c) {
				shades.top.css({
					left: px(c.x),
					width: px(c.w),
					height: px(c.y)
				});
				shades.bottom.css({
					top: px(c.y2),
					left: px(c.x),
					width: px(c.w),
					height: px(boundy - c.y2)
				});
				shades.right.css({
					left: px(c.x2),
					width: px(boundx - c.x2)
				});
				shades.left.css({
					width: px(c.x)
				});
			}

			function createShade() {
				return $('<div />').css({
					position: 'absolute',
					backgroundColor: options.shadeColor || options.bgColor
				}).appendTo(holder);
			}

			function enableShade() {
				if (!enabled) {
					enabled = true;
					holder.insertBefore($img);
					updateAuto();
					Selection.setBgOpacity(1, 0, 1);
					$img2.hide();

					setBgColor(options.shadeColor || options.bgColor, 1);
					if (Selection.isAwake()) {
						setOpacity(options.bgOpacity, 1);
					} else setOpacity(1, 1);
				}
			}

			function setBgColor(color, now) {
				colorChangeMacro(getShades(), color, now);
			}

			function disableShade() {
				
				if (enabled) {
					holder.remove();
					$img2.show();
					enabled = false;
					if (Selection.isAwake()) {
						Selection.setBgOpacity(options.bgOpacity, 1, 1);
					} else {
						Selection.setBgOpacity(1, 1, 1);
						Selection.disableHandles();
					}
					colorChangeMacro($div, 0, 1);
				}
			}

			function setOpacity(opacity, now) {
				
				if (enabled) {
					if (options.bgFade && !now) {
						holder.animate({
							opacity: 1 - opacity
						}, {
							queue: false,
							duration: options.fadeTime
						});
					} else holder.css({
						opacity: 1 - opacity
					});
				}
			}

			function refreshAll() {
				options.shade ? enableShade() : disableShade();
				if (Selection.isAwake()) setOpacity(options.bgOpacity);
			}

			function getShades() {
				return holder.children();
			}

			return {
				update: updateAuto,
				updateRaw: updateShade,
				getShades: getShades,
				setBgColor: setBgColor,
				enable: enableShade,
				disable: disableShade,
				resize: resizeShades,
				refresh: refreshAll,
				opacity: setOpacity
			};
		}());
		// }}}
		// Selection Module {{{
		//选择对象
		var Selection = (function() {
			var awake,
				hdep = 370,
				borders = {},
				handle = {},
				dragbar = {},
				seehandles = false;

			// Private Methods
			function insertBorder(type) //{{{
			{
				var jq = $('<div />').css({
					position: 'absolute',
					opacity: options.borderOpacity
				}).addClass(cssClass(type));
				$img_holder.append(jq);
				
				return jq;
			}
			//}}}
			function dragDiv(ord, zi) //{{{
			{
				
				var jq = $('<div />').mousedown(createDragger(ord)).css({
					cursor: ord + '-resize',
					position: 'absolute',
					zIndex: zi
				}).addClass('ord-' + ord);

				if (Touch.support) {
					jq.bind('touchstart.jcrop', Touch.createDragger(ord));
					//jqd.bind('touchstart.jcrop', Touch.createDragger(ord));
				}
				
				$hdl_holder.append(jq);
				return jq;
			}
			//}}}
			function insertHandle(ord) //{{{
			{
				var hs = options.handleSize,

					div = dragDiv(ord, hdep++).css({
						opacity: options.handleOpacity
					}).addClass(cssClass('handle'));

				if (hs) {
					div.width(hs).height(hs);
				}
				
				return div;
			}
			//}}}
			function insertDragbar(ord) //{{{
			{
				return dragDiv(ord, hdep++).addClass('jcrop-dragbar');
			}
			//}}}
			function createDragbars(li) //{{{
			{
				var i;
				for (i = 0; i < li.length; i++) {
					dragbar[li[i]] = insertDragbar(li[i]);
				}
			}
			//}}}
			function createBorders(li) //{{{
			{
				var cl, i;
				for (i = 0; i < li.length; i++) {
					switch (li[i]) {
						case 'n':
							cl = 'hline';
							break;
						case 's':
							cl = 'hline bottom';
							insertBorder('hline middle');
							break;
						case 'e':
							cl = 'vline right';
							insertBorder('vline middle');
							break;
						case 'w':
							cl = 'vline';
							break;
					}
					borders[li[i]] = insertBorder(cl);
				}
			}
			//}}}
			function createHandles(li) //{{{
			{
				var i;
				for (i = 0; i < li.length; i++) {
					handle[li[i]] = insertHandle(li[i]);
				}
			}
			//}}}
			function moveto(x, y) //{{{
			{
				if (!options.shade) {
					$img2.css({
						top: px(-y),
						left: px(-x)
					});
				}
				$sel.css({
					top: px(y),
					left: px(x)
				});
			}
			//}}}
			function resize(w, h) //{{{
			{
				$sel.width(Math.round(w)).height(Math.round(h));
			}
			//}}}
			function refresh() //{{{
			{
				var c = Coords.getFixed();

				Coords.setPressed([c.x, c.y]);
				Coords.setCurrent([c.x2, c.y2]);

				updateVisible();
			}
			//}}}

			// Internal Methods
			function updateVisible(select) //{{{
			{
				if (awake) {
					return update(select);
				}
			}
			//}}}
			function update(select) //{{{
			{
				var c = Coords.getFixed();

				resize(c.w, c.h);
				moveto(c.x, c.y);
				if (options.shade) Shade.updateRaw(c);

				awake || show();

				if (select) {
					options.onSelect.call(api, unscale(c));
				} else {
					options.onChange.call(api, unscale(c));
				}
			}
			//}}}
			function setBgOpacity(opacity, force, now) //{{{
			{
				if (!awake && !force) return;
				if (options.bgFade && !now) {
					$img.animate({
						opacity: opacity
					}, {
						queue: false,
						duration: options.fadeTime
					});
				} else {
					$img.css('opacity', opacity);
				}
			}
			//}}}
			function show() //{{{
			{
				$sel.show();

				if (options.shade) Shade.opacity(bgopacity);
				else setBgOpacity(bgopacity, true);

				awake = true;
			}
			//}}}
			function release() //{{{
			{
				disableHandles();
				$sel.hide();

				if (options.shade) Shade.opacity(1);
				else setBgOpacity(1);

				awake = false;
				options.onRelease.call(api);
			}
			//}}}
			function showHandles() //{{{
			{
				if (seehandles) {
					$hdl_holder.show();
				}
			}
			//}}}
			function enableHandles() //{{{
			{
				seehandles = true;
				if (options.allowResize) {
					$hdl_holder.show();
					return true;
				}
			}
			//}}}
			function disableHandles() //{{{
			{
				seehandles = false;
				$hdl_holder.hide();
			}
			//}}}
			function animMode(v) //{{{
			{
				if (v) {
					animating = true;
					disableHandles();
				} else {
					animating = false;
					enableHandles();
				}
			}
			//}}}
			function done() //{{{
			{
				animMode(false);
				refresh();
			}
			//}}}
			// Insert draggable elements {{{
			// Insert border divs for outline

			if (options.dragEdges && $.isArray(options.createDragbars))
				createDragbars(options.createDragbars);

			if ($.isArray(options.createHandles))
				createHandles(options.createHandles);

			if (options.drawBorders && $.isArray(options.createBorders))
				createBorders(options.createBorders);

			//}}}

			// This is a hack for iOS5 to support drag/move touch functionality
			$(document).bind('touchstart.jcrop-ios', function(e) {
				if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation();
			});
			

			var $track = newTracker().mousedown(createDragger('move')).css({
				cursor: 'move',
				position: 'absolute',
				zIndex: 360,
				opacity: 0.55,
				 background: '#000'
			});
//			var $circle = newCircle().mousedown(createDragger('move')).css({
//				cursor: 'move',
//				position: 'absolute',
//				
//				zIndex: 9999999999
//			});
			if (Touch.support) {
				$track.bind('touchstart.jcrop', Touch.createDragger('move'));
				//$circle.bind('touchstart.jcrop', Touch.createDragger('move'));
			}
			
			//$img_holder.append($circle);
			$img_holder.append($track);
			//$track.html($circle.get(0))
			disableHandles();

			return {
				updateVisible: updateVisible,
				update: update,
				release: release,
				refresh: refresh,
				isAwake: function() {
					return awake;
				},
				setCursor: function(cursor) {
					$track.css('cursor', cursor);
					//$circle.css('cursor', cursor);
				},
				enableHandles: enableHandles,
				enableOnly: function() {
					seehandles = true;
				},
				showHandles: showHandles,
				disableHandles: disableHandles,
				animMode: animMode,
				setBgOpacity: setBgOpacity,
				done: done
			};
		}());

		//}}}
		// Tracker Module {{{
		var Tracker = (function() {
			var onMove = function() {},
				onDone = function() {},
				trackDoc = options.trackDocument;

			function toFront(touch) //{{{
			{
				$trk.css({
					zIndex: 450
				});
//				$circle.css({
//					zIndex: 1001
//				});

				if (touch)
					$(document)
					.bind('touchmove.jcrop', trackTouchMove)
					.bind('touchend.jcrop', trackTouchEnd);

				else if (trackDoc)
					$(document)
					.bind('mousemove.jcrop', trackMove)
					.bind('mouseup.jcrop', trackUp);
			}
			//}}}
			function toBack() //{{{
			{
				$trk.css({
					zIndex: 290
				});
//				$circle.css({
//					zIndex: 1001
//				});
				$(document).unbind('.jcrop');
			}
			//}}}
			function trackMove(e) //{{{
			{
				onMove(mouseAbs(e));
				return false;
			}
			//}}}
			function trackUp(e) //{{{
			{
				e.preventDefault();
				e.stopPropagation();

				if (btndown) {
					btndown = false;

					onDone(mouseAbs(e));

					if (Selection.isAwake()) {
						options.onSelect.call(api, unscale(Coords.getFixed()));
					}

					toBack();
					onMove = function() {};
					onDone = function() {};
				}

				return false;
			}
			//}}}
			/**
			 * 
			 * @param {Object} move  返回移动的函数
			 * @param {Object} done  松开的函数
			 * @param {Object} touch
			 */
			function activateHandlers(move, done, touch) //{{{
			{
			
				btndown = true;
				onMove = move;
				onDone = done;
				toFront(touch);
				return false;
			}
			//}}}
			function trackTouchMove(e) //{{{
			{
				onMove(mouseAbs(Touch.cfilter(e)));
				return false;
			}
			//}}}
			function trackTouchEnd(e) //{{{
			{
				return trackUp(Touch.cfilter(e));
			}
			//}}}
			function setCursor(t) //{{{
			{
				
				$trk.css('cursor', t);
				//$circle.css('cursor', t);
			}
			//}}}

			if (!trackDoc) {
				$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
				//$circle.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);
			}




			$img.before($trk);
			//$trk.html($circle);
			return {
				activateHandlers: activateHandlers,
				setCursor: setCursor
			};
		}());


		//}}}
		// KeyManager Module {{{
		var KeyManager = (function() {
			var $keymgr = $('<input type="radio" />').css({
					position: 'fixed',
					left: '-120px',
					width: '12px'
				}).addClass('jcrop-keymgr'),

				$keywrap = $('<div />').css({
					position: 'absolute',
					overflow: 'hidden'
				}).append($keymgr);

			function watchKeys() //{{{
			{
				if (options.keySupport) {
					$keymgr.show();
					$keymgr.focus();
				}
			}
			//}}}
			function onBlur(e) //{{{
			{
				$keymgr.hide();
			}
			//}}}
			function doNudge(e, x, y) //{{{
			{
				if (options.allowMove) {
					Coords.moveOffset([x, y]);
					Selection.updateVisible(true);
				}
				e.preventDefault();
				e.stopPropagation();
			}
			//}}}
			function parseKey(e) //{{{
			{
				if (e.ctrlKey || e.metaKey) {
					return true;
				}
				shift_down = e.shiftKey ? true : false;
				var nudge = shift_down ? 10 : 1;

				switch (e.keyCode) {
					case 37:
						doNudge(e, -nudge, 0);
						break;
					case 39:
						doNudge(e, nudge, 0);
						break;
					case 38:
						doNudge(e, 0, -nudge);
						break;
					case 40:
						doNudge(e, 0, nudge);
						break;
					case 27:
						if (options.allowSelect) Selection.release();
						break;
					case 9:
						return true;
				}

				return false;
			}
			//}}}

			if (options.keySupport) {
				$keymgr.keydown(parseKey).blur(onBlur);
				if (ie6mode || !options.fixedSupport) {
					$keymgr.css({
						position: 'absolute',
						left: '-20px'
					});
					$keywrap.append($keymgr).insertBefore($img);
				} else {
					$keymgr.insertBefore($img);
				}
			}


			return {
				watchKeys: watchKeys
			};
		}());
		//}}}
		// }}}
		// API methods {{{
		function setClass(cname) //{{{
		{
			$div.removeClass().addClass(cssClass('holder')).addClass(cname);
		}
		//}}}
		function animateTo(a, callback) //{{{
		{
			var x1 = a[0] / xscale,
				y1 = a[1] / yscale,
				x2 = a[2] / xscale,
				y2 = a[3] / yscale;

			if (animating) {
				return;
			}

			var animto = Coords.flipCoords(x1, y1, x2, y2),
				c = Coords.getFixed(),
				initcr = [c.x, c.y, c.x2, c.y2],
				animat = initcr,
				interv = options.animationDelay,
				ix1 = animto[0] - initcr[0],
				iy1 = animto[1] - initcr[1],
				ix2 = animto[2] - initcr[2],
				iy2 = animto[3] - initcr[3],
				pcent = 0,
				velocity = options.swingSpeed;

			x1 = animat[0];
			y1 = animat[1];
			x2 = animat[2];
			y2 = animat[3];

			Selection.animMode(true);
			var anim_timer;

			function queueAnimator() {
				window.setTimeout(animator, interv);
			}
			var animator = (function() {
				return function() {
					pcent += (100 - pcent) / velocity;

					animat[0] = Math.round(x1 + ((pcent / 100) * ix1));
					animat[1] = Math.round(y1 + ((pcent / 100) * iy1));
					animat[2] = Math.round(x2 + ((pcent / 100) * ix2));
					animat[3] = Math.round(y2 + ((pcent / 100) * iy2));

					if (pcent >= 99.8) {
						pcent = 100;
					}
					if (pcent < 100) {
						setSelectRaw(animat);
						queueAnimator();
					} else {
						Selection.done();
						Selection.animMode(false);
						if (typeof(callback) === 'function') {
							callback.call(api);
						}
					}
				};
			}());
			queueAnimator();
		}
		//}}}
		function setSelect(rect) //{{{
		{
			setSelectRaw([rect[0] / xscale, rect[1] / yscale, rect[2] / xscale, rect[3] / yscale]);
			options.onSelect.call(api, unscale(Coords.getFixed()));
			Selection.enableHandles();
		}
		//}}}
		function setSelectRaw(l) //{{{
		{
			Coords.setPressed([l[0], l[1]]);
			Coords.setCurrent([l[2], l[3]]);
			Selection.update();
		}
		//}}}
		function tellSelect() //{{{
		{
			return unscale(Coords.getFixed());
		}
		//}}}
		function tellScaled() //{{{
		{
			return Coords.getFixed();
		}
		//}}}
		function setOptionsNew(opt) //{{{
		{
			setOptions(opt);
			interfaceUpdate();
		}
		//}}}
		function disableCrop() //{{{
		{
			options.disabled = true;
			Selection.disableHandles();
			Selection.setCursor('default');
			Tracker.setCursor('default');
		}
		//}}}
		function enableCrop() //{{{
		{
			options.disabled = false;
			interfaceUpdate();
		}
		//}}}
		function cancelCrop() //{{{
		{
			Selection.done();
			Tracker.activateHandlers(null, null);
		}
		//}}}
		function destroy() //{{{
		{
			$div.remove();
			$origimg.show();
			$origimg.css('visibility', 'visible');
			$(obj).removeData('Jcrop');
		}
		//}}}
		function setImage(src, callback) //{{{
		{
			Selection.release();
			disableCrop();
			var img = new Image();
			img.onload = function() {
				var iw = img.width;
				var ih = img.height;
				var bw = options.boxWidth;
				var bh = options.boxHeight;
				$img.width(iw).height(ih);
				$img.attr('src', src);
				$img2.attr('src', src);
				presize($img, bw, bh);
				boundx = $img.width();
				boundy = $img.height();
				$img2.width(boundx).height(boundy);
				$trk.width(boundx + (bound * 2)).height(boundy + (bound * 2));
				$div.width(boundx).height(boundy);
				Shade.resize(boundx, boundy);
				enableCrop();

				if (typeof(callback) === 'function') {
					callback.call(api);
				}
			};
			img.src = src;
		}
		//}}}
		function colorChangeMacro($obj, color, now) {
			var mycolor = color || options.bgColor;
			if (options.bgFade && supportsColorFade() && options.fadeTime && !now) {
				$obj.animate({
					backgroundColor: mycolor
				}, {
					queue: false,
					duration: options.fadeTime
				});
			} else {
				$obj.css('backgroundColor', mycolor);
			}
		}

		function interfaceUpdate(alt) //{{{
		// This method tweaks the interface based on options object.
		// Called when options are changed and at end of initialization.
		{
			if (options.allowResize) {
				if (alt) {
					Selection.enableOnly();
				} else {
					Selection.enableHandles();
				}
			} else {
				Selection.disableHandles();
			}

			Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default');
			Selection.setCursor(options.allowMove ? 'move' : 'default');

			if (options.hasOwnProperty('trueSize')) {
				xscale = options.trueSize[0] / boundx;
				yscale = options.trueSize[1] / boundy;
			}

			if (options.hasOwnProperty('setSelect')) {
				setSelect(options.setSelect);
				Selection.done();
				delete(options.setSelect);
			}

			Shade.refresh();

			if (options.bgColor != bgcolor) {
				colorChangeMacro(
					options.shade ? Shade.getShades() : $div,
					options.shade ?
					(options.shadeColor || options.bgColor) :
					options.bgColor
				);
				bgcolor = options.bgColor;
			}

			if (bgopacity != options.bgOpacity) {
				bgopacity = options.bgOpacity;
				if (options.shade) Shade.refresh();
				else Selection.setBgOpacity(bgopacity);
			}

			xlimit = options.maxSize[0] || 0;
			ylimit = options.maxSize[1] || 0;
			xmin = options.minSize[0] || 0;
			ymin = options.minSize[1] || 0;

			if (options.hasOwnProperty('outerImage')) {
				$img.attr('src', options.outerImage);
				delete(options.outerImage);
			}

			Selection.refresh();
		}
		//}}}
		//}}}

		if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection);
		//if (Touch.support) $circle.bind('touchstart.jcrop', Touch.newSelection);

		$hdl_holder.hide();
		interfaceUpdate(true);

		var api = {
			setImage: setImage,
			animateTo: animateTo,
			setSelect: setSelect,
			setOptions: setOptionsNew,
			tellSelect: tellSelect,
			tellScaled: tellScaled,
			setClass: setClass,

			disable: disableCrop,
			enable: enableCrop,
			cancel: cancelCrop,
			release: Selection.release,
			destroy: destroy,

			focus: KeyManager.watchKeys,

			getBounds: function() {
				return [boundx * xscale, boundy * yscale];
			},
			getWidgetSize: function() {
				return [boundx, boundy];
			},
			getScaleFactor: function() {
				return [xscale, yscale];
			},
			getOptions: function() {
				// careful: internal values are returned
				return options;
			},

			ui: {
				holder: $div,
				selection: $sel
			}
		};

		if (is_msie) $div.bind('selectstart', function() {
			return false;
		});

		$origimg.data('Jcrop', api);
		return api;
	};





	$.fn.Jcrop = function(options, callback) //{{{
		{
			var api;
			// Iterate over each object, attach Jcrop
			this.each(function() {
				// If we've already attached to this object
				if ($(this).data('Jcrop')) {
					// The API can be requested this way (undocumented)
					if (options === 'api') return $(this).data('Jcrop');
					// Otherwise, we just reset the options...
					else $(this).data('Jcrop').setOptions(options);
				}
				// If we haven't been attached, preload and attach
				else {
					if (this.tagName == 'IMG')
						$.Jcrop.Loader(this, function() {
							$(this).css({
								display: 'block',
								visibility: 'hidden'
							});
							api = $.Jcrop(this, options);
							if ($.isFunction(callback)) callback.call(api);
						});
					else {
						$(this).css({
							display: 'block',
							visibility: 'hidden'
						});
						api = $.Jcrop(this, options);
						if ($.isFunction(callback)) callback.call(api);
					}
				}
			});

			// Return "this" so the object is chainable (jQuery-style)
			return this;
		};
	//}}}
	// $.Jcrop.Loader - basic image loader {{{

	/**
	 * @desc {String} 检查图片是否加载完成
	 * @param {Object} imgobj 图片
	 * @param {Object} success
	 * @param {Object} error
	 */
	$.Jcrop.Loader = function(imgobj, success, error) {
		var $img = $(imgobj),
			img = $img[0];

		function completeCheck() {

			if (img.complete) {
				$img.unbind('.jcloader');
				if ($.isFunction(success)) success.call(img);
			} else window.setTimeout(completeCheck, 50);
		}

		$img
			.bind('load.jcloader', completeCheck)
			.bind('error.jcloader', function(e) {
				$img.unbind('.jcloader');
				if ($.isFunction(error)) error.call(img);
			});

		if (img.complete && $.isFunction(success)) {
			$img.unbind('.jcloader');
			success.call(img);
		}
	};

	//}}}
	// Global Defaults {{{
	$.Jcrop.defaults = {

		// Basic Settings
		allowSelect: true,
		allowMove: true,
		allowResize: true,

		trackDocument: true,

		// Styling Options
		baseClass: 'jcrop',
		addClass: null,
		bgColor: 'black',
		bgOpacity: 0.6,
		bgFade: false,
		borderOpacity: 0.4,
		handleOpacity: 0.5,
		handleSize: null,

		aspectRatio: 0,
		keySupport: true,
		createHandles: ['n', 's', 'e', 'w', 'nw', 'ne', 'se', 'sw'],
		createDragbars: ['n', 's', 'e', 'w'],
		createBorders: ['n', 's', 'e', 'w'],
		drawBorders: true,
		dragEdges: true,
		fixedSupport: true,
		touchSupport: null,

		shade: null,

		boxWidth: 0,
		boxHeight: 0,
		boundary: 2,
		fadeTime: 400,
		animationDelay: 20,
		swingSpeed: 3,

		minSelect: [0, 0],
		maxSize: [0, 0],
		minSize: [0, 0],

		// Callbacks / Event Handlers
		onChange: function() {},
		onSelect: function() {},
		onDblClick: function() {},
		onRelease: function() {}
	};

	// }}}
}(jQuery));
